package com.example.feild.encryption;

import com.alibaba.fastjson.JSONObject;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author: 阿力
 * @date: 2019/12/30 11:15
 * @describe:
 */
public class Jdk8Features {
    class User {
        private String name;
        private int age;
        private String province;
        private String birth;
        private BigDecimal amt;

        public User(String name, int age, String province, String birth, BigDecimal amt) {
            this.name = name;
            this.age = age;
            this.province = province;
            this.birth = birth;
            this.amt = amt;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public String getProvince() {
            return province;
        }

        public void setProvince(String province) {
            this.province = province;
        }

        public String getBirth() {
            return birth;
        }

        public void setBirth(String birth) {
            this.birth = birth;
        }

        public BigDecimal getAmt() {
            return amt;
        }

        public void setAmt(BigDecimal amt) {
            this.amt = amt;
        }
    }

    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
    }

    private List<User> getVoList() {
        return new ArrayList<User>() {{
            add(new User("张三", 30, "湖北", "1990-05-06 12:00:00", BigDecimal.valueOf(100.0d)));
            add(new User("李四", 28, "湖南", "1991-05-06 12:00:00", BigDecimal.valueOf(200.0d)));
            add(new User("王五", 20, "湖北", "1992-05-06 12:00:00", BigDecimal.valueOf(300.0d)));
            add(new User("赵六", 16, "江西", "1993-05-06 12:00:00", BigDecimal.valueOf(400.0d)));
            add(new User("张三", 30, "湖北", "1994-05-06 12:00:00", BigDecimal.valueOf(500.0d)));
        }};
    }

    private List<Map<String, Object>> getMapList() {
        return new ArrayList<Map<String, Object>>() {{
            add(new HashMap<String, Object>() {{
                put("name", "张三");
                put("age", 30);
                put("province", "湖北");
                put("birth", "1990-05-06 12:00:00");
                put("amt", BigDecimal.valueOf(100.0d));
            }});
            add(new HashMap<String, Object>() {{
                put("name", "李四");
                put("age", 28);
                put("province", "湖南");
                put("birth", "1991-05-06 12:00:00");
                put("amt", BigDecimal.valueOf(200.0d));
            }});
            add(new HashMap<String, Object>() {{
                put("name", "王五");
                put("age", 20);
                put("province", "湖北");
                put("birth", "1992-05-06 12:00:00");
                put("amt", BigDecimal.valueOf(300.0d));
            }});
            add(new HashMap<String, Object>() {{
                put("name", "赵六");
                put("age", 16);
                put("province", "江西");
                put("birth", "1993-05-06 12:00:00");
                put("amt", BigDecimal.valueOf(400.0d));
            }});
            add(new HashMap<String, Object>() {{
                put("name", "张三");
                put("age", 30);
                put("province", "湖北");
                put("birth", "1994-05-06 12:00:00");
                put("amt", BigDecimal.valueOf(500.0d));
            }});
        }};
    }

    /***
     * 列出vo和map对比demo
     * @param args
     */
    public static void main(String[] args) {
        // 数据构造
        Jdk8Features jf = new Jdk8Features();
        List<User> voList = jf.getVoList();
        List<Map<String, Object>> mapList = jf.getMapList();

        // 1.过滤（查询年龄大于25岁用户）
        List<User> filterVoList = voList.stream().filter(v -> v.getAge() > 25).collect(Collectors.toList());
        List<Map<String, Object>> filterMapList = mapList.stream().filter(m -> Integer.parseInt(m.get("age").toString()) > 25).collect(Collectors.toList());

        // 2.分组（根据用户所在区域分组）
        Map<String, List<User>> groupVoList = voList.stream().collect(Collectors.groupingBy(User::getProvince));
        Map<String, List<Map<String, Object>>> groupMapList = mapList.stream().collect(Collectors.groupingBy(m -> m.get("province").toString(), TreeMap::new, Collectors.toList()));
        Assert.isTrue(groupVoList.size() == groupMapList.size(), "分组不一致");

        // 3.排序（按照年龄从大到小）
        List<User> sortVoList = voList.stream().sorted(Comparator.comparing(User::getAge, Comparator.reverseOrder())).collect(Collectors.toList());
        List<Map<String, Object>> sortMapList = mapList.stream().sorted(Comparator.comparing(m -> m.get("age").toString(), Comparator.reverseOrder())).collect(Collectors.toList());
        Assert.isTrue(sortVoList.size() == sortMapList.size(), "排序不一致");

        // 4.去重（根据姓名去重）
        List<User> distinctVoList = voList.stream().filter(distinctByKey(User::getName)).collect(Collectors.toList());
        List<Map<String, Object>> distinctMapList = mapList.stream().filter(distinctByKey(m -> m.get("name"))).collect(Collectors.toList());
        Assert.isTrue(distinctVoList.size() == distinctMapList.size(), "去重不一致");

        // 5.对象集合，转其他类型集合（获取所有姓名）
        List<String> changeVoList = voList.stream().map(User::getName).collect(Collectors.toList());
        List<String> changeMapList = mapList.stream().map(m -> m.get("name").toString()).collect(Collectors.toList());
        Assert.isTrue(changeVoList.size() == changeMapList.size(), "转换不一致");

        // 6.求和（获取年龄总和）
        int sumVoList = voList.stream().mapToInt(User::getAge).sum();
        int sumMapList = mapList.stream().mapToInt(m -> Integer.parseInt(m.get("age").toString())).sum();
        Assert.isTrue(sumVoList == sumMapList, "求和不一致");
        BigDecimal sumAmtVoList = voList.stream().map(User::getAmt).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal sumAmtMapList = mapList.stream().map(m -> new BigDecimal(m.get("amt").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);
        System.out.println("BigDecimal求和" + sumAmtVoList);
        System.out.println("BigDecimal求和" + sumAmtMapList);

        // 7.多重排序——>年龄升序、出生时间排序（倒叙）
        List<User> doubleSortVoList = voList.stream().sorted(Comparator.comparing(User::getAge, Comparator.naturalOrder()).thenComparing(User::getBirth, Comparator.reverseOrder())).collect(Collectors.toList());
        List<Map<String, Object>> doubleSortMapList = mapList.stream().sorted((o1, o2) -> {
            int result = o1.get("age").toString().compareTo(o2.get("age").toString());
            if (result == 0) {
                result = o2.get("birth").toString().compareTo(o1.get("birth").toString());
            }
            return result;
        }).collect(Collectors.toList());
        doubleSortMapList.forEach(x -> System.out.println(JSONObject.toJSONString(x)));
    }
}
